param ([switch]$SendEmail = $false, [string]$OneOffEmailAddr = "default")
# By default do not send email.
cls
#$DebugPreference = "SilentlyContinue"  #This is default
$DebugPreference = "Continue"  #This causes more output
#$DebugPreference = "Inquire"  #This causes output and queries to continue or stop
#$DebugPreference = "Stop"  #This causes output and stops
#requires -version 1
Set-PSDebug -Strict -Trace 0 -Step:$false

#Load up the Report Library Functions.  ReportLibrary.ps1 must be in the same dir as the report script
Write-Debug "Load Report Libary Functions"
#. ((Split-Path -Parent (Resolve-Path -Path $MyInvocation.InvocationName)) + "\ReportLibrary.ps1")
$ScriptName = $MyInvocation.MyCommand.Name
$ScriptDir = Split-Path $MyInvocation.MyCommand.Path
. "$ScriptDir\ReportLibrary.ps1"

Confirm-ExchangeSnapIn

#---------------8<---------------Variables
$ServerName = $Env:COMPUTERNAME
$FromServer = "&nbsp;<span class=""style5"">" + $ServerName + "</span>"
$now = get-date
$date = get-date -format d #get-date -uformat "%m-%d-%Y"
$TZ = Get-TimeZoneName
$ServerSkipList = "C:\WINDOWS\Scripts\ExServersToSkip.csv"
$Logo = "<span class=""style14"">perot</span><span class=""style10"">systems</span><span class=""style11"">&#0174;</span>&nbsp;"
#---------------8<---------------Company Info and Mail
$ReportType = "Exchange"
$Company = "CHW"
$Subject = $Company + " " + $ReportType + " Report - " + $date
$Header = $Company + " " + $ReportType + " Report - Report as on " + $now + " " + $TZ + $FromServer + "<br>" + "`r`n"
$SMTPHost = "162.135.4.20"
$From = """Exchange Operations"" <ExchangeOp@ps.net>"
$emailMessage = "Exchange Report"
if ($oneOffEmailAddr.tolower() -eq "default") {
	$To = "<david_f_ray@dell.com>"
	$Cc = ""
	$Bcc = ""
} else {
	$To = $oneOffEmailAddr
	$Cc = ""
	$BCc = ""
}
$attach = ""
#---------------8<---------------Variables

#---------------8<---------------Function WhiteSpace
Function Get-WhiteSpace([string]$server, [string]$MailboxDatabaseName, [array]$WSEvents) {
	$Array = @()
	$Result = @()
	If ($WSEvents -ne $null) {
		#$Check = $WSpace -is [array]
		$WSpace = $WSEvents | Where-Object {$_.Message.Contains($MailboxDatabaseName)}
		If ($WSpace -is [array]) {
			Write-Debug 'WSpace is Array: ' #($WSpace -is [array])
			ForEach ($item in $WSpace) {
				$Array = $item.message.split("`"")
				$EndString = $Array[2].indexof("megabytes ")-6
				#Write-Debug $mbnamearray[1]
				[int]$Result = $Array[2].Substring(5,$EndString)
			}
		} else {
			Write-Debug 'WSpace is not Array: ' #($WSpace -is [array])
			$Array = $WSpace.message.split("`"")
			$EndString = $Array[2].indexof("megabytes ")-6
			#Write-Debug $mbnamearray[1]
			[int]$Result = $Array[2].Substring(5,$EndString)			 
		}
	} else {
		Write-Debug "WSpace is null"
		$Result = "No defrag last day"
	}
	$Result
} #end of Function Get-Whitespace

#---------------8<---------------Variables
$ServerName = $Env:COMPUTERNAME
$FromServer = "&nbsp;<span class=""style5"">" + $ServerName + "</span>"
$now = get-date
$date = get-date -format d #get-date -uformat "%m-%d-%Y"
$TZ = Get-TimeZoneName
$ServerSkipList = "C:\WINDOWS\Scripts\ExServersToSkip.csv"
$Logo = "<span class=""style14"">perot</span><span class=""style10"">systems</span><span class=""style11"">&#0174;</span>&nbsp;"
#---------------8<---------------Company Info and Mail
$ReportType = "Exchange"
$Company = "CHW"
$Subject = $Company + " " + $ReportType + " Report - " + $date
$Header = $Company + " " + $ReportType + " Report - Report as on " + $now + " " + $TZ + $FromServer + "<br>" + "`r`n"
$SMTPHost = "162.135.4.20"
$From = """Exchange Operations"" <ExchangeOp@ps.net>"
$emailMessage = "Exchange Report"
if ($oneOffEmailAddr.tolower() -eq "default") {
	$To = "<david_f_ray@dell.com>"
	$Cc = ""
	$Bcc = ""
} else {
	$To = $oneOffEmailAddr
	$Cc = ""
	$BCc = ""
}
$attach = ""
#---------------8<---------------Variables
$filelocation = $Company + $ReportType + "Report.html"
$Code = @()
$Write = @()

#---------------8<---------------HEAD HTML Code
function Head() {
#$Write = ""
$Write += "<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01//EN""  ""http://www.w3.org/TR/html4/strict.dtd"">" + "`r`n"
$Write += "<html>" + "`r`n"
$Write += "<head>" + "`r`n"
$Write += "<meta http-equiv=""Content-Type"" content=""text/html; charset=iso-8859-1"">" + "`r`n"
$title = "<title>" + $Subject + "</title>" + "`r`n"
$Write += $title
$Head = @'
<style>
BODY{font-family:tahoma;} 
TABLE{border-width: 1px;cellspacing: 0;cellpadding: 3;}
TH{border-width: 1px;font-size: 11px;text-align: center;background-color: #999999;font-weight: bold;}
TD{border-width: 1px;font-size: 9px;text-align: center;border-width: 1px;border-style: solid;}
.style5{color: #FFFFFF;}
.style9{background-color: #000000;}
.style10{font-family: Verdana;font-size: 14px;font-weight: bold;}
.style11{font-size: 9px;vertical-align: text-top;}
.style12{font-size: 9px;color: #C0C0C0;}
.style13{font-family: Tahoma;font-size: 9px;color: #FFFFFF;border: 1px solid #C0C0C0;}
.style14{color: #FE000B;font-family: Verdana;font-size: 14px;font-weight: bold;}
</style>
'@
$Write += $Head
$Write += "</head><body>" + "`r`n"
$Write += "<H6>" + "`r`n"
$Write += $Header
$Write += "<br>" + "`r`n"
$Write += "Backup: <span style=""background-color:yellow"">YELLOW</span> = &gt; 1 day &nbsp; <span style=""background-color:red"">RED</span> = &gt; 2 days <br>" + "`r`n"
$Write += "Whitespace: <span style=""background-color:yellow"">YELLOW</span> = &gt; 20% &nbsp; <span style=""background-color:red"">RED</span> = &gt; 30% <br>" + "`r`n"
$Write += "Free Space: <span style=""background-color:yellow"">YELLOW</span> = &gt; 15% &nbsp; <span style=""background-color:red"">RED</span> = &gt; 5% <br>" + "`r`n"
$Write += "</H6>" + "`r`n"
$Write += "<table>" + "`r`n"
Return $Write
} #end of Function Head

#---------------8<---------------HEADER HTML Code
function Header() {
#$Write = ""
$Write += "<tr>" + "`r`n"
$Write += "<th>Server\StorageGroup\Database</th>" + "`r`n"
$Write += "<th>Size (GB)</th>" + "`r`n"
$Write += "<th>Mailbox Count</th>" + "`r`n"
$Write += "<th>LastFullBackup</th>" + "`r`n"
$Write += "<th>WhiteSpace (MB)</th>" + "`r`n"
$Write += "<th>Capacity (GB)</th>" + "`r`n"
$Write += "<th>Free Space (GB)</th>" + "`r`n"
$Write += "<th>Free Space (%)</th>" + "`r`n"
$Write += "</tr>" + "`r`n"
Return $Write
} # end of Function Header

#---------------8<---------------BODY HTML Code
function Body($objItem,$MDBSize,$MBXCount,$BackupDays,$WhiteSpace,$DiskCapacity,$FreeOnStorage,$FreeOnStoragePct) {
	$Write += "<tr>" + "`r`n"
	$Write += "<td>$objItem</td>" + "`r`n"
	#Write-Debug "Size (GB): " $MDBSize
	$Write += "<td>$MDBSize</td>" + "`r`n"
	Write-Debug "MBXCount:  $MBXCount"
	if ($MBXCount -ne $null)
		{$Write += "<td>$MBXCount</td>" + "`r`n"}
	else
		{$Write += "<td>-</td>" + "`r`n"}
	#Write-Debug $CheckLastBackup
	#Write-Debug $CheckLastBackup.days
	Write-Debug "BackupDays $BackupDays"
	if ($BackupDays -eq "-")
		{$Write += "<td>-</td>" + "`r`n"}
	elseif ($BackupDays -le -2)
		{$Write += "<td bgcolor=red>$LastBackup</td>" + "`r`n"}
	elseif ($BackupDays -eq -1)
		{$Write += "<td bgcolor=yellow>$LastBackup</td>" + "`r`n"}
	elseif ($BackupDays -eq 0)
		{$Write += "<td bgcolor=#BBFBA8>$LastBackup</td>" + "`r`n"}
	else
		{$Write += "<td bgcolor=#BBFBA8>$LastBackup</td>" + "`r`n"}
	# Write-Debug '$WhiteSpace2: ' $WhiteSpace
	# Write-Debug $WhiteSpace.GetType()
	
	if ($WhiteSpace -is [int] -and $WhiteSpace -ge $Thres30Pct)
		{$Write += "<td bgcolor=red>$WhiteSpace</td>" + "`r`n"}
	elseif ($WhiteSpace -is [int] -and $WhiteSpace -ge $Thres20Pct)
		{$Write += "<td bgcolor=yellow>$WhiteSpace</td>" + "`r`n"}
	elseif ($WhiteSpace -eq "No defrag last day")
		{$Write += "<td bgcolor=yellow>$WhiteSpace</td>" + "`r`n"}
	else
		{$Write += "<td>$WhiteSpace</td>" + "`r`n"}
	$Write += "<td>$DiskCapacity</td>" + "`r`n"
	$Write += "<td>$FreeOnStorage</td>" + "`r`n"
	$FreePct = [int]$FreeOnStoragePct.Remove($FreeOnStoragePct.Length-1,1)
	If ($FreePct -le 5)
		{$Write += "<td bgcolor=red>$FreeOnStoragePct</td>" + "`r`n"}
	ElseIf ($FreePct -le 15)
		{$Write += "<td bgcolor=yellow>$FreeOnStoragePct</td>" + "`r`n"}
	else
		{$Write += "<td bgcolor=#BBFBA8>$FreeOnStoragePct</td>" + "`r`n"}
	$Write += "</tr>" + "`r`n"
	Return $Write
} #end of Function body

#---------------8<---------------FOOTER HTML Code
Function Footer() {
$finish = Get-Date
$Write += "</table>" + "`r`n"
$Write += "<br>" + "`r`n"
$Write += "<table class=""style9"">" + "`r`n"
$Write += "<tr>" + "`r`n"
$Write += "<td style=""color #CCCCCC;"" class=""style13"">Finished processing " + $TotalServers + " servers @ " + $finish + " " + $TZ + "</td>" + "`r`n"
$Write += "</tr>" + "`r`n"
$Write += "</table>" + "`r`n"
$Write += "$Logo<span class=""style12"">Based on code by Ajlan</span>" + "`r`n"
$Write += "</body></html>" + "`r`n"

$Write += @"
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
<meta name=Generator content="Microsoft Word 14 (filtered)">
<style>
<!--
 /* Font Definitions */
 @font-face
	{font-family:"Cambria Math";
	panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
	{font-family:Calibri;
	panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
	{font-family:Tahoma;
	panose-1:2 11 6 4 3 5 4 4 2 4;}
 /* Style Definitions */
 p.MsoNormal, li.MsoNormal, div.MsoNormal
	{margin-top:0in;
	margin-right:0in;
	margin-bottom:10.0pt;
	margin-left:0in;
	line-height:115%;
	font-size:11.0pt;
	font-family:"Calibri","sans-serif";}
a:link, span.MsoHyperlink
	{color:blue;
	text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
	{color:purple;
	text-decoration:underline;}
p.MsoAcetate, li.MsoAcetate, div.MsoAcetate
	{mso-style-link:"Balloon Text Char";
	margin:0in;
	margin-bottom:.0001pt;
	font-size:8.0pt;
	font-family:"Tahoma","sans-serif";}
span.MsoPlaceholderText
	{color:gray;}
span.BalloonTextChar
	{mso-style-name:"Balloon Text Char";
	mso-style-link:"Balloon Text";
	font-family:"Tahoma","sans-serif";}
.MsoChpDefault
	{font-family:"Calibri","sans-serif";}
.MsoPapDefault
	{margin-bottom:10.0pt;
	line-height:115%;}
@page WordSection1
	{size:8.5in 11.0in;
	margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
	{page:WordSection1;}
-->
</style>
</head>
<body lang=EN-US link=blue vlink=purple>
<div class=WordSection1>
<p class=MsoNormal>CHW Messaging Reporting</p>
<p class=MsoNormal>$($emailMessage)</p>
<div class=MsoNormal align=center style='text-align:center'>
<hr size=2 width="100%" align=center>
</div>
<p class=MsoNormal><span style='font-size:9.0pt;line-height:115%;color:#BFBFBF'>Scripted
in Powershell by <a href="mailto:david_f_ray@dell.com"><span style='color:#0000BF'>David
Ray</span></a> {$($MyInvocation.MyCommand.Name)}</span></p>
<p class=MsoNormal>&nbsp;</p>
</div>
</body>
</html>
"@


Return $Write
} #end of Function Footer

#---------------8<---------------Function Email
Function sendmail($body) {
    $SmtpClient = new-object system.net.mail.smtpClient 
    $MailMessage = New-Object system.net.mail.mailmessage 
    $SmtpClient.Host = $SMTPHost #"<Your Email Server>"
    $MailMessage.From = $From
    $MailMessage.To.add($To)
	If ($Cc){
		$MailMessage.Cc.add($Cc)
	}
	If ($Bcc){
		$MailMessage.Bcc.add($Bcc)
	}
    $MailMessage.Subject = $Subject
    $MailMessage.IsBodyHtml = $True
    $MailMessage.Body = $body #Get-Content .\report.html 	
	If ($attach){
		$Attachment = new-object System.Net.Mail.Attachment($attach)
		$MailMessage.Attachements.Add($Attachment)
	}
   $SmtpClient.Send($mailmessage) 
} #end of Function sendmail


$Code += Head
#Write-Debug '$Code1: ' $Code
#$Code += Header
#Write-Debug '$Code2: ' $Code

#---------------8<---------------
# Build list of Exchange Servers
#---------------8<---------------Function Main

## Adding the following to skip the numerous servers that are not really in the environment
## but clutter the output.  Reads ExServersToSkip.csv into an array and excludes servers
## matching those names from the lists. -dfr 03/24/2010
$skiplist = @()
Import-Csv $ServerSkipList | ForEach-Object {$skiplist += $_.Servername}

#These are Ajlan's original lines
#$exchange2007servers = @(Get-MailboxServer | sort) #Get-ExchangeServer |where-object {$_.admindisplayversion.major -eq 8 -and $_.IsMailboxServer -eq $true }
#$exchange2003servers = @(Get-ExchangeServer | where-object {$_.admindisplayversion.major -ne 8 } | sort)

#These are mine with the skiplist test added -dfr
$exchange2007servers = @(Get-MailboxServer | Where-Object {$skiplist -notcontains $_.name} | Sort-Object Name | Select-Object Name) 
$exchange2003servers = @(Get-ExchangeServer | Where-Object {$skiplist -notcontains $_.name -and $_.admindisplayversion.major -ne 8 } | Sort-Object Name | Select-Object Name)
#$exchange2007servers = @(Get-MailboxServer | Where-Object {$_.Name -eq "CHW-MSG-821"} | Sort-Object Name | Select-Object Name) 
#$exchange2003servers = @(Get-ExchangeServer | Where-Object {$_.name -eq "CHW-MSG-301"} | Sort-Object Name | Select-Object Name)
$exchangeServers = $exchange2003servers + $exchange2007servers | Sort

#---------------8<---------------Function Main Exchange 2007
foreach ($server in $exchangeServers) {
	Write-Debug "======================"
	Write-Debug $server.name
	Write-Debug "Getting Mailbox Databases"
	$ServerDatabases = Get-MailboxDatabase -Status -server $server.name | sort
		If ($ServerDatabases -ne $null) {
			$Code += Header
			$Volumes = Get-WMIObject Win32_Volume -computerName $server.name #pulled this here so it only runs once per server
			#$WmidtQueryDT = [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime([DateTime]::UtcNow.AddDays(-1)) #A lower limit on how far back to look in the eventlog
			#Write-Debug '$WmidtQueryDT: ' $WmidtQueryDT
			#get all 1221 events from the server back to $WmidtQueryDT (1 day).  Brought this out of Get-Whitespace Function so it will only run once per server (very slow)
			Write-Debug "Getting 1221 events"
			#$WhiteSpaceEvents = Get-WmiObject -computer $server.name -query ("Select * from Win32_NTLogEvent Where Logfile='Application' and Eventcode = '1221' and TimeWritten >='" + $WmidtQueryDT + "'")
			$GetEventTime = Measure-Command {$WhiteSpaceEvents = Get-EventLog -ComputerName $server.name -log Application -Source "MsExchangeIS Mailbox Store" -EntryType Information -after (get-date).addHours(-36) | ? {$_.EventID -eq 1221 } }
			Write-Debug ("Time to retrieve events: {0:D2}:{1:D2}" -f $GetEventTime.Minutes,$GetEventTime.Seconds)
			foreach ($MailboxDatabase in $ServerDatabases) {
				Write-Debug "*****************"
				$Thres20Pct = $null
				$Thres30Pct = $null
				$DiskCapacity = $null
				$FreeOnStorage = $null
				$FreeOnStoragePercent = $null
				$MDBSize = $null
				$WhiteSpace =$null
				$MBXCount = $null
				$BackupDays = $null
				
				Write-Debug "DatabaseName:  $MailboxDatabase.name"
				###diff here
				$edbfilepath = $MailboxDatabase.edbfilepath.pathname
				#$edbpath = $edbfilepath.ToUpper()
				Write-Debug "edbpath:  $($edbfilepath.ToUpper())"
				#convert absolute path to UNC path
				$path = "\\" + $server.name + "\" + $MailboxDatabase.EdbFilePath.PathName.Replace(":","$")
				Write-Debug "path:   $path"
				$dbsize = Get-ChildItem $path
				Write-Debug "dbsize:   $dbsize"
				####mailboxcount different
				#$mailboxcount = Get-MailboxStatistics -database "$MailboxDatabase" | measure-object
				$mailboxcount = Get-MailboxDatabase -Server $server.name | where { $_.Name -eq $MailboxDatabase.name } | Get-Mailbox -ResultSize:Unlimited | measure-object
				
				#$start = $path.LastIndexOf('\')
				#$dbName = $path.Substring($start +1).remove($path.Substring($start +1).length -4)
				#$mailboxpath = "$server\$MailboxDatabase.name"
				#Write-Debug "DatabaseFile: " $mailboxpath
				$edbpathlength = 0
				#$volumes = Get-WMIObject Win32_Volume -computerName $server  #does not need to run more than once per server
				foreach ($volItem in $Volumes) {
					If ( $edbfilepath.ToUpper().startswith($volItem.name.ToUpper()) ) {
						Write-Debug ($volItem.name.ToUpper() +"   -   "+ $edbfilepath.startswith($volItem.name) +"   -   "+ $volItem.name.length)			
						If ($edbpathlength -lt $volItem.name.length) {	
							$edbpathlength = $volItem.name.length
							$edbfilepathvolumename = $volItem.name
							$edbfilepathfreespace =  $volItem.freespace
							$edbfilepathcapacity = $volItem.capacity
						}
					}
				}
				
				$VolumeName = $edbfilepathvolumename
				$FreeOnStorage = "{0:N2}" -f ($edbfilepathfreespace/1GB)
				$DiskCapacity = "{0:N2}" -f ($edbfilepathcapacity/1GB)

				Write-Debug "VolumeName:  $VolumeName"
				Write-Debug "DiskCapacity:  $DiskCapacity"
				Write-Debug "FreeOnStorage:  $FreeOnStorage"
				$FreeOnStoragePercent = "{0:P2}" -f ([int] $FreeOnStorage / [int] $DiskCapacity)
				Write-Debug "FreeOnStoragePercent:  $FreeOnStoragePercent"
				$MDBSize = ("{0:N2}" -f ($dbsize.Length/1GB))
				Write-Debug "MDBSize:  $MDBSize"
				$MBXCount = $mailboxcount.count
				$LastBackup = $MailboxDatabase.LastFullBackup
				Write-Debug "LastBackup:  $LastBackup"
				$WhiteSpace = Get-WhiteSpace $server $MailboxDatabase.name $WhiteSpaceEvents
				Write-Debug "WhiteSpace:  $WhiteSpace"
				If ($LastBackup -ne $null) { 
					$CheckLastBackup = New-TimeSpan $(get-date) $($LastBackup)
					$BackupDays = $CheckLastBackup.days
				}	
				else { $BackupDays = "-"}
				$Thres20Pct = [int] $MDBSize * 1024 * .2
				$Thres30Pct = [int] $MDBSize * 1024 * .3
				Write-Debug "Thres20Pct:  $Thres20Pct"
				Write-Debug "Thres30Pct:  $Thres30Pct"
				
				$Code += (body $MailboxDatabase $MDBSize $MBXCount $BackupDays $WhiteSpace $DiskCapacity $FreeOnStorage $FreeOnStoragePercent)
			}
		}
	#Write-Debug "Press any key to continue ..."
	#$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
	#if ($x.character -eq "x") {exit}
}  # End of Main Exchange 2007/2003 loop



$TotalServers = $exchangeServers.Count

#---------------8<---------------Wrap Up
$Code += Footer
# Write-Debug '$Code3: ' $Code
#Write-Debug $Code

$Code | out-file $filelocation

$body = $Code


Write-Debug "Done"

If ($SendEmail)   #switch parameter passed as parameter
	{Sendmail $body
	Write-Debug "Email Sent!"}
else
	{Write-Debug "No Email!"}

set-psdebug -Off